package com.gitee.feizns.quickstart.demo.rtu;

import purejavacomm.CommPort;
import purejavacomm.CommPortIdentifier;
import purejavacomm.SerialPort;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Enumeration;

/**
 * @author feizns
 * @since 2024/9/7
 */
public class SerialPortExample {

//    public static void main(String[] args) {
//        SerialPort comPort = SerialPort.getCommPort("COM3"); // 替换为你的串口名
//        comPort.setBaudRate(9600);
//        comPort.setNumDataBits(8);
//        comPort.setNumStopBits(SerialPort.ONE_STOP_BIT);
//        comPort.setParity(SerialPort.NO_PARITY);
//
//        if (comPort.openPort()) {
//            System.out.println("串口已打开");
//        } else {
//            System.out.println("无法打开串口");
//            return;
//        }
//
//        // 构建 Modbus RTU 请求帧
//        byte[] requestFrame = buildModbusRequestFrame(1, 3, 0, 10); // 假设的参数
//        try {
//            comPort.writeBytes(requestFrame, requestFrame.length);
//            System.out.println("请求已发送");
//        } catch (Exception e) {
//            System.out.println("发送请求时出错");
//            e.printStackTrace();
//        } finally {
//            comPort.closePort();
//            System.out.println("串口已关闭");
//        }
//    }

    private static byte[] buildModbusRequestFrame(int slaveId, int functionCode, int startAddress, int quantityOfRegisters) {
        byte[] frame = new byte[8];
        frame[0] = (byte) slaveId;
        frame[1] = (byte) functionCode;
        frame[2] = (byte) (startAddress >> 8);
        frame[3] = (byte) (startAddress & 0xFF);
        frame[4] = (byte) (quantityOfRegisters >> 8);
        frame[5] = (byte) (quantityOfRegisters & 0xFF);
        // 计算CRC校验码并添加到帧中
        int crc = calculateCRC(frame, 6);
        frame[6] = (byte) (crc & 0xFF);
        frame[7] = (byte) (crc >> 8);
        return frame;
    }

    private static int calculateCRC(byte[] message, int length) {
        int crc = 0xFFFF;
        for (int i = 0; i < length; i++) {
            crc ^= (message[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((crc & 1) == 1) {
                    crc = (crc >> 1) ^ 0xA001;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        return crc;
    }

    public static class Test {
        public static void main(String[] args) {
//            byte b = (byte) (1 >> 8);
//            System.out.println(b);
            System.out.println(buildModbusRequestFrame(1, 3, 1, 1));
        }
    }

//    public static void main(String[] args) {
//
//    }



    public static void main(String[] args) {
        // 串口名称，例如 "COM3" 或 "/dev/ttyS0"
        String portName = "COM8";

        // 尝试打开串口
        try {
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            if (portIdentifier.isCurrentlyOwned()) {
                System.out.println("Error: Port is currently in use");
            } else {
                CommPort commPort = portIdentifier.open("SerialPortExample", 2000);
                if ( commPort instanceof SerialPort ) {
                    SerialPort serialPort = (SerialPort) commPort;
                    // 设置串口参数
                    serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

                    // 获取输入流和输出流
                    InputStream in = serialPort.getInputStream();
                    OutputStream out = serialPort.getOutputStream();

                    //写入1号站6功能码0号位设置为1
//                    byte[] frame = buildModbusRequestFrame(1, 6, 0, 0);
                    byte[] frame = buildModbusRequestFrame(1, 3, 0, 1);
                    // 写入数据
//                    byte[] dataToSend = new byte[]{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 6, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8 };
                    out.write(frame);
                    out.flush();

//                    (dataToSend..getBytes());
                    // 读取数据
                    byte[] buffer = new byte[1024];
                    int numRead = 0;
                    while (numRead != -1) {
                        numRead = in.read(buffer);
                        if (numRead != -1) {
                            System.out.println(Arrays.toString(buffer));
//                            String received = new String(buffer, 0, numRead);
//                            System.out.println("Received: " + received);
                        }
                    }

                    // 关闭串口
                    out.close();
                    in.close();
                    serialPort.close();
                } else {
                    System.out.println("Error: Only serial ports are handled by this example.");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
//
//    public static byte[] stringToHex(String str) {
//        int len = str.length();
//        byte[] data = new byte[len / 2];
//        for (int i = 0; i < len; i += 2) {
//            data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4)
//                    + Character.digit(str.charAt(i+1), 16));
//        }
//        return data;
//    }

    private static void listSerialPorts() {
        Enumeration<CommPortIdentifier> portIdentifiers = CommPortIdentifier.getPortIdentifiers();
        while ( portIdentifiers.hasMoreElements() ) {
            CommPortIdentifier portIdentifier = portIdentifiers.nextElement();
            if (portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                System.out.println(portIdentifier.getName());
            }
        }
    }

}
